package com.qwe.graduation.shiro.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qwe.graduation.entity.User;
import com.qwe.graduation.utils.CommonConstant;
import com.qwe.graduation.utils.RedisUtil;
import com.qwe.graduation.utils.exception.Constants;
import com.qwe.graduation.utils.exception.Result;
import com.qwe.graduation.utils.exception.ServiceException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author lzf
 * @date 2022/10/28 8:58
 * @description JWTUtil
 */

/**
 * @Author zwj
 * @Desc JWT工具类
 **/

public class JwtUtil {

    // Token过期时间180天（用户登录过期时间是此时间的两倍，以token在reids缓存时间为准）
    public static final long EXPIRE_TIME = 24 * 180 * 60 * 60 * 1000;
    public static final int days = 360;
    private static StringRedisTemplate stringRedisTemplate = SpringContextUtils.getBean(StringRedisTemplate.class);

    /**
     * 校验token是否正确
     *
     * @param token     密钥
     * @param Password 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String userId, String Password) {
        try {
            // 根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(Password);
            JWTVerifier verifier = JWT.require(algorithm).withClaim("userId", userId).build();
            // 效验TOKEN
            verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userId").asString();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 生成签名,360天后过期
     *
     * @param userId    用户id
     * @param password 用户的密码
     * @return 加密的token
     */
    public static String sign(String userId, String password) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        Algorithm algorithm = Algorithm.HMAC256(password);
        // 附带userId信息  可以将user信息转成map存到这里
      String token = JWT.create().withClaim("userId", userId).withExpiresAt(date).sign(algorithm);
//        String token = JWT.create().withClaim("userId", userId).sign(algorithm);
        stringRedisTemplate.opsForValue().set(CommonConstant.PREFIX_USER_TOKEN + token, token, days, TimeUnit.DAYS);
        return token;

    }

    /**
     * 根据request中的token获取用户账号
     *
     * @param request
     * @return
     */
    public static String getUserIdByToken(HttpServletRequest request) {
        String accessToken = getTokenByRequest(request);
        String userId = getUserId(accessToken);
        return userId;
    }

    /**
     * 校验token在redis里是否失效
     *
     * @param request
     * @return
     */
//    public static String checkoutRedisToken(HttpServletRequest request) {
//        String accessToken = getTokenByRequest(request);
//        redisUtil.hasKey
//        return userId;
//    }


//    /**
//     * 根据request中的token获取用户
//     *
//     * @param request
//     * @return
//     */
//    public static User getUserByToken(HttpServletRequest request) {
//        String accessToken = getTokenByRequest(request);
//        String userId = getUserId(accessToken);
//        return userId;
//    }

    /**
     * 获取 request 里传递的 token
     *
     * @param request
     * @return
     */
    public static String getTokenByRequest(HttpServletRequest request) {
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        return token;
    }

    /**
     *
     * @param response
     * @param code
     * @param errorMsg
     */
    public static void responseError(ServletResponse response, String code, String errorMsg) {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        // issues/I4YH95浏览器显示乱码问题
        httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
        Result jsonResult = new Result(code, errorMsg);
        OutputStream os = null;
        try {
            os = httpServletResponse.getOutputStream();
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setStatus(401);
            os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
            os.flush();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
